package org.mili.ticketeer.dao;

import org.mili.ticketeer.dao.query.v2.QueryBuilder;
import org.mili.ticketeer.dto.Contact;
import org.mili.ticketeer.dto.ContactRole;
import org.mili.ticketeer.dto.Identifieable;
import org.mili.ticketeer.dto.Role;
import org.mili.ticketeer.util.Lambda;
import org.mili.ticketeer.util.Log;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

public class RoleDao extends AbstractDao {

    public RoleDao() {
        super(Role.UniqueFields.values(), Role.Fields.values(), Role.TABLE);
    }

    public List<Role> getRoles() throws DaoException {
        return read(new RoleRowTransformer());
    }

    public ModificationResult write(final Role role) throws DaoException {
        return createOrUpdate(role);
    }

    public Boolean assign(final Contact contact, final Role role) throws DaoException {
        return doInDao(new Lambda<Boolean>() {
            @Override
            public Boolean exec(Object... params) throws SQLException {
                return update("insert into `contact_role` (`contact`, `role`) values(?, ?);", contact.getId(),
                        role.getId()) == 1;
            }
        });
    }

    public Boolean unassign(final Contact contact, final Role role) throws DaoException {
        return doInDao(new Lambda<Boolean>() {
            @Override
            public Boolean exec(Object... params) throws SQLException {
                return update("delete from `contact_role` where `contact`=? and `role`=?", contact.getId(),
                        role.getId()) == 1;
            }
        });
    }

    public Role findById(final int id) throws DaoException {
        return doInDao(new Lambda<Role>() {
            @Override
            public Role exec(Object... params) throws SQLException {
                return querySingle(new RowTransformer<Role>() {
                    @Override
                    public Role transform(ResultSet resultSet) throws SQLException {
                        Role role = new Role();
                        role.setId(id);
                        role.setName(resultSet.getString(Role.Fields.NAME.name()));
                        return role;
                    }
                },
                QueryBuilder.createQueryBuilder()
                        .select()
                        .fields(Role.Fields.NAME)
                        .from(table)
                        .where()
                        .eq(Identifieable.Fields.ID, id).build());
            }
        });
    }

    public Role findByName(final String name) throws DaoException {
        return doInDao(new Lambda<Role>() {
            @Override
            public Role exec(Object... params) throws SQLException {
                return querySingle(new RowTransformer<Role>() {
                    @Override
                    public Role transform(ResultSet resultSet) throws SQLException {
                        Role role = new Role();
                        role.setId(resultSet.getInt(Identifieable.Fields.ID.name()));
                        role.setName(name);
                        return role;
                    }
                },
                    QueryBuilder.createQueryBuilder()
                            .select()
                            .fields(Identifieable.Fields.ID)
                            .from(table)
                            .where()
                            .eq(Role.Fields.NAME, name).build());
            }
        });
    }

    public List<ContactRole> getContactRolesFor(final Contact contact) throws DaoException {
        return doInDao(new Lambda<List<ContactRole>>() {
            @Override
            public List<ContactRole> exec(Object... params) throws SQLException {
                return query(new RowTransformer<ContactRole>() {
                    @Override
                    public ContactRole transform(ResultSet resultSet) throws SQLException {
                        ContactRole contactRole = new ContactRole();
                        contactRole.setContact(resultSet.getInt("contactid"));
                        contactRole.setRole(resultSet.getInt("roleid"));
                        Log.log(this, "getContactRolesFor", "contact=%s, %s", contact.getId(), contactRole);
                        return contactRole;
                    }
                }, "select role.id as roleid, (select contact_role.contact from contact_role where contact_role.role=roleid and contact_role.contact=?) as contactid from role", contact.getId());
            }
        });
    }

    public List<ContactRole> getAssignedContactRolesFor(final Contact contact) throws DaoException {
        return doInDao(new Lambda<List<ContactRole>>() {
            @Override
            public List<ContactRole> exec(Object... params) throws SQLException {
                return query(new RowTransformer<ContactRole>() {
                    @Override
                    public ContactRole transform(ResultSet resultSet) throws SQLException {
                        ContactRole contactRole = new ContactRole();
                        contactRole.setContact(contact.getId());
                        contactRole.setRole(resultSet.getInt(ContactRole.Fields.ROLE.name()));
                        Log.log(this, "getAssignedContactRolesFor", "contact=%s, %s", contact.getId(), contactRole);
                        return contactRole;
                    }
                }, QueryBuilder.createQueryBuilder().select().fields(ContactRole.Fields.ROLE).from(ContactRole.TABLE)
                        .where().eq(ContactRole.Fields.CONTACT, contact.getId()).build());
            }
        });
    }

    public List<ContactRole> getContactRoles() throws DaoException {
        return doInDao(new Lambda<List<ContactRole>>() {
            @Override
            public List<ContactRole> exec(Object... params) throws SQLException {
                return query(new RowTransformer<ContactRole>() {
                    @Override
                    public ContactRole transform(ResultSet resultSet) throws SQLException {
                        ContactRole contactRole = new ContactRole();
                        contactRole.setRole(resultSet.getInt("role"));
                        return contactRole;
                    }
                },
                    QueryBuilder.createQueryBuilder()
                            .select()
                            .fields(Identifieable.Fields.ID)
                            .from(table)
                            .build());
            }
        });
    }

    class RoleRowTransformer implements RowTransformer<Role> {
        @Override
        public Role transform(ResultSet resultSet) throws SQLException {
            Role role = new Role();
            role.setId(resultSet.getInt(Identifieable.Fields.ID.name()));
            role.setName(resultSet.getString(Role.Fields.NAME.name()));
            return role;
        }
    }
}
